package de.ret_world.openrpgstudio.mapeditor.scripts;

import de.ret_world.openrpgstudio.editor.Media;
import de.ret_world.openrpgstudio.editor.Project;
import de.ret_world.openrpgstudio.editor.script.ScriptObject;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;

/**
 * A TileSet for storing Tiles which are used in TileMaps.
 *
 * @author Emu
 */
public class TileSet implements ScriptObject {

    public static final String TYPE = "TileSet";
    private String ID;
    private int tileHeight, tileWidth = 32;
    private int offset, gap = 0;
    private Media tilesetImg;
    private ArrayList<Rectangle> tiles = new ArrayList<>();

    @Override
    public void create(LuaValue val) {
        if (!val.get("id").isnil()) {
            ID = val.get("id").toString();
        }
        if (!val.get("tileWidth").isnil()) {
            tileWidth = val.get("tileWidth").toint();
        }
        if (!val.get("tileHeight").isnil()) {
            tileHeight = val.get("tileHeight").toint();
        }
        if (!val.get("offset").isnil()) {
            offset = val.get("offset").toint();
        }
        if (!val.get("gap").isnil()) {
            gap = val.get("gap").toint();
        }
        if (!val.get("image").isnil()) {
            Media m = Project.getInstance().getMediaManager().getMedia(val.get("image").toString());

            if (tilesetImg != null) {
                tilesetImg.getUsers().remove(ID);
            }

            tilesetImg = m;
            m.getUsers().add(ID);
            generateTiles();
        }
    }

    @Override
    public LuaTable toLua() {
        LuaTable lua = new LuaTable();
        lua.set("id", LuaTable.valueOf(ID));
        lua.set("tileWidth", LuaTable.valueOf(tileWidth));
        lua.set("tileHeight", LuaTable.valueOf(tileHeight));
        lua.set("offset", LuaTable.valueOf(offset));
        lua.set("gap", LuaTable.valueOf(gap));
        lua.set("image", LuaTable.valueOf(tilesetImg.getID()));

        return lua;
    }

    @Override
    public String toScript() {
        String s = "tileset = {} -- init new tileset\n"
                + "tileset.id = '" + ID + "'\n"
                + "tileset.tileWidth = " + tileWidth + "\n"
                + "tileset.tileHeight = " + tileHeight + "\n"
                + "tileset.offset = " + offset + "\n"
                + "tileset.gap = " + gap + "\n";
        if (tilesetImg != null) {
            s += "tileset.image = '" + tilesetImg.getID() + "'\n";
        }

        return s;
    }

    public int getTilesPerRow() {
        BufferedImage img = null;
        try {
            img = ImageIO.read(Project.getInstance().getFolder("root").resolve(tilesetImg.getFile()).toFile());
        } catch (IOException ex) {
            Logger.getLogger(TileSet.class).error(ex);
        }
        int iw = img.getWidth();
        return (iw - (2 * offset) + gap) / (tileWidth + gap);
    }

    public int getTilesPerColumn() {
        BufferedImage img = null;
        try {
            img = ImageIO.read(Project.getInstance().getFolder("root").resolve(tilesetImg.getFile()).toFile());
        } catch (IOException ex) {
            Logger.getLogger(TileSet.class).error(ex);
        }

        int ih = img.getHeight();
        return (ih - (2 * offset) + gap) / (tileHeight + gap);
    }

    private void generateTiles() {
        int tilesPerRow = getTilesPerRow();
        int tilesPerCol = getTilesPerColumn();

        tiles.clear();
        for (int c = 0; c < tilesPerCol; c++) {
            for (int r = 0; r < tilesPerRow; r++) {
                int x = (r * (tileWidth + gap)) + offset;
                int y = (c * (tileHeight + gap)) + offset;

                Rectangle rect = new Rectangle(x, y, tileWidth, tileHeight);
                tiles.add(rect);
            }
        }
    }

    public ArrayList<Rectangle> getTiles() {
        return tiles;
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }

    public int getTileHeight() {
        return tileHeight;
    }

    public void setTileHeight(int tileHeight) {
        this.tileHeight = tileHeight;
    }

    public int getTileWidth() {
        return tileWidth;
    }

    public void setTileWidth(int tileWidth) {
        this.tileWidth = tileWidth;
    }

    public int getGap() {
        return gap;
    }

    public void setGap(int gap) {
        this.gap = gap;
    }

    public int getOffset() {
        return offset;
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    public Media getImage() {
        return tilesetImg;
    }

    public void setImage(Media image) {
        if (tilesetImg != null) {
            tilesetImg.getUsers().remove(ID);
        }

        this.tilesetImg = image;
        image.getUsers().add(ID);
        generateTiles();
    }

    @Override
    public String toString() {
        return getID();
    }
}
